﻿/*
	Copyright (c) 2005 by Sean Kent. All rights reserved.
	Permission to use, copy, modify and distribute this software for any
	purpose is hereby granted without fee, provided this copyright and
	permissions notice appear in all copies and derivatives.
*/
#region Using directives

using System;
using System.IO;
using System.Reflection;

#endregion

namespace Slobby.Common.NetworkFormatter {
	public class ObjectReader {
		public ObjectReader(AssemblyTypeInformation typeInformationStore) {
			this.typeInformationStore = typeInformationStore;
		}

		public object Deserialize(BinaryReader deserializationStream) {
			return ReadSerializedObject(deserializationStream);
		}

		private object ReadSerializedObject(BinaryReader deserializationStream) {
			int id = deserializationStream.ReadInt32();
			Type graphType = typeInformationStore.GetTypeFromId(id);
			object instance = graphType.Assembly.CreateInstance(graphType.FullName);
			ReadFields(deserializationStream, graphType, instance);
			return instance;
		}

		private void ReadFields(BinaryReader deserializationStream, Type graphType, object instance) {
			foreach (FieldInfo field in typeInformationStore.GetFieldsFromType(graphType)) {
				ReadObject(deserializationStream, field.FieldType, instance, field);
			}
		}

		private void ReadObject(BinaryReader deserializationStream, Type graphType, object instance, FieldInfo field) {
			object result;
			MethodInfo deserializationMethod = typeof(BinaryReader).GetMethod("Read" + graphType.Name);
			if (deserializationMethod != null) {
				result = ReadPrimitive(deserializationStream, deserializationMethod);
			} else {
				result = ReadSerializedObject(deserializationStream);
			}
			field.SetValue(instance, result);
		}

		private static object ReadPrimitive(BinaryReader deserializationStream, MethodInfo deserializationMethod) {
			object result;
			result = deserializationMethod.Invoke(deserializationStream, null);
			return result;
		}

		private AssemblyTypeInformation typeInformationStore;
	}
}
